import sys
import uix
import uiutil
import xtriui
import blue
import draw
import form
import string
import listentry
import menu
import util
import math
import os
import yaml
import benchmark1
import log
import uiconst
import uicls
import spiffy
OUTPUT_FILE = 'benchmark.yaml'
logChannel = log.GetChannel('Benchmark.Progress')

class BenchmarkDetails(uicls.Window):
    __guid__ = 'form.bmdetails'
    types = {0: 'Benchmark',
     1: 'Alter Setting'}
    toggle = {'turretsEnabled': mls.UI_SYSMENU_TURRETEFFECTS,
     'effectsEnabled': mls.UI_GENERIC_EFFECTS,
     'missilesEnabled': mls.UI_SYSMENU_MISSILEEFFECTS,
     'trails': mls.UI_SYSMENU_TRAILSONOFF,
     'lod': mls.UI_SYSMENU_USELOD,
     'cameraShakeEnabled': mls.UI_SYSMENU_CAMERASHAKE,
     'explosionEffectsEnabled': mls.UI_SYSMENU_EXPLOSIONEFFECTS,
     'droneModelsEnabled': mls.UI_SYSMENU_DRONEMODELS,
     'notifyMessagesEnabled': mls.UI_SYSMENU_ENABLENOTIFYMESSAGES}

    def ApplyAttributes(self, attributes):
        uicls.Window.ApplyAttributes(self, attributes)
        w = 322
        h = 466
        self.HideClippedIcon()
        self.HideMainIcon()
        self.SetTopparentHeight(0)
        self.SetMinSize([w, h])
        self.SetHeight(h)
        self.LockWidth(w)
        self.MakeUnResizeable()
        self.SetCaption('Benchmarking')
        self.file = None
        self.account = {}
        self.data = {}
        self.db = {}
        self.store = {}
        self.order = {}
        ids = benchmark1.GetIDs()
        for key in ids:
            self.order[key] = ids[key][1]

        self.Begin()



    def Begin(self, *args):
        margin = const.defaultPadding
        self.settingup = True
        self.GetDetails()
        (dbop, fiop,) = self.outputmodes = self.Modes()
        setupframe = self.setupframe = uicls.Container(name='setupframe', align=uiconst.TOALL, parent=self.sr.main, pos=(margin,
         24,
         margin,
         24))
        setupframe.height = margin
        connframe = self.connframe = uicls.Container(name='connframe', align=uiconst.TOALL, parent=self.sr.main, pos=(margin,
         24,
         margin,
         24))
        connframe.height = margin
        prefsframe = self.prefsframe = uicls.Container(name='prefsframe', align=uiconst.TOALL, parent=self.sr.main, pos=(margin,
         24,
         margin,
         24))
        prefsframe.height = margin
        uicls.Frame(parent=setupframe, color=(1.0, 1.0, 1.0, 0.2))
        uicls.Frame(parent=connframe, color=(1.0, 1.0, 1.0, 0.2))
        uicls.Frame(parent=prefsframe, color=(1.0, 1.0, 1.0, 0.2))
        tabs = [['Runs',
          setupframe,
          self.sr.main,
          'setup'],
         ['Connection',
          connframe,
          self.sr.main,
          'connection'],
         ['Settings',
          prefsframe,
          self.sr.main,
          'prefs']]
        maintabs = form.TabGroup(uicls.Container(name='tabs', align=uiconst.TOTOP, height=18, top=margin, parent=self.sr.main))
        maintabs.Startup(tabs, 'maintabs')
        self.tree = spiffy.TreeScroll(name='tree', align=uiconst.TOALL, parent=prefsframe, padding=(margin,
         margin,
         margin,
         margin))
        self.tree.Startup()
        self.tree.sr.id = 'tree'
        self.DoTreeRefresh()
        self.scroll = uicls.Scroll(name='scroll', parent=setupframe, padding=(margin,
         margin,
         margin,
         margin))
        self.scroll.height = 32
        self.scroll.Startup()
        self.scroll.Load(contentList=[], headers=['ID',
         'Event',
         'Type',
         'Info'], noContentHint=mls.UI_CORP_NOITEMSFOUND)
        self.scroll.sr.id = 'benchmarks'
        mbtns = [['Add Event',
          self.DoScrollAdd,
          uiconst.TOLEFT,
          0,
          (0, 0),
          'ui_44_32_43'],
         ['Remove Event',
          self.DoScrollRemove,
          uiconst.TOLEFT,
          0,
          (0, 0),
          'ui_44_32_44'],
         ['Clear All Events',
          self.DoScrollClear,
          uiconst.TOLEFT,
          0,
          (1, 1),
          'ui_73_16_49'],
         ['Move Event Up',
          self.DoNodeMoveUp,
          uiconst.TOLEFT,
          90,
          (-1, -1),
          'ui_38_16_224'],
         ['Move Event Down',
          self.DoNodeMoveDown,
          uiconst.TOLEFT,
          90,
          (-1, -1),
          'ui_38_16_223'],
         ['Import YAML',
          self.DoYamlImport,
          uiconst.TORIGHT,
          0,
          (0, 0),
          'ui_44_32_01'],
         ['Export YAML',
          self.DoYamlExport,
          uiconst.TORIGHT,
          0,
          (0, 0),
          'ui_44_32_02'],
         ['Delete Key',
          self.DoDeleteFromStore,
          uiconst.TORIGHT,
          0,
          (1, 1),
          'ui_44_32_08'],
         ['Load Key',
          self.DoLoadFromStore,
          uiconst.TORIGHT,
          0,
          (1, 0),
          'ui_44_32_06'],
         ['Save Key',
          self.DoSaveToStore,
          uiconst.TORIGHT,
          0,
          (0, 0),
          'ui_44_32_23'],
         ['Set As Default Key',
          self.DoDefaultSet,
          uiconst.TORIGHT,
          0,
          (0, 0),
          'ui_44_32_03']]
        button_cont = uicls.Container(name='buttons', align=uiconst.TOBOTTOM, height=24, parent=setupframe)
        button_cont.top += margin
        for line in mbtns:
            (label, callback, align, rotate, coords, iconID,) = line
            (left, top,) = coords
            push = uicls.Container(name='push', align=align, pos=(0,
             0,
             margin,
             0), parent=button_cont)
            btn = uicls.Container(name=label, align=align, pos=(0, 0, 24, 0), parent=button_cont)
            uicls.Frame(parent=btn, color=(1.0, 1.0, 1.0, 0.125))
            transform = draw.TransformContainer('transform', btn)
            icon = uicls.Icon(icon=iconID, parent=transform, size=24, left=left, top=top)
            icon.OnClick = callback
            icon.hint = label
            icon.autoPos = uix.AUTOPOSCENTER
            icon.OnMouseEnter = (self.ShowSelected, 1)
            icon.OnMouseExit = (self.ShowSelected, 0)
            icon.sr.hilite = uicls.Fill(parent=btn, align=uiconst.TOALL, state=uiconst.UI_HIDDEN)
            if rotate:
                radians = (math.pi / 180)
                radians = (radians * rotate)
                transform.transform.RotationZ(radians)

        uix.GetContainerHeader('Benchmark Run Options', connframe, bothlines=0)
        self.nextcb = uicls.Checkbox(text='Run at next logon', parent=connframe, retval=0, configName='logonrunCheckBox', checked=bool(prefs.GetValue('bmnextrun', 0)), callback=self.DoNextLogonChange, pos=(0, 0, 145, 0))
        self.rescb = uicls.Checkbox(text='Run at all resolutions', parent=connframe, retval=0, configName='bmreslockCheckBox', checked=prefs.GetValue('bmreslock', 0), callback=self.DoResolutionChange, pos=(0, 0, 145, 0))
        uix.GetContainerHeader('Result Storage Options', connframe)
        self.filecb = uicls.Checkbox(text='Save to file', parent=connframe, retval=0, configName='filesaveCheckBox', checked=fiop, callback=self.DoFileSaveChange, pos=(0, 0, 145, 0))
        self.databasecb = uicls.Checkbox(text='Save to database', parent=connframe, retval=0, configName='dbsaveCheckBox', checked=dbop, callback=self.DoDatabaseSaveChange, pos=(0, 0, 145, 0))
        for checkbox in [self.nextcb,
         self.rescb,
         self.filecb,
         self.databasecb]:
            func = checkbox.OnChange
            func(checkbox)
            diode = uiutil.GetChild(checkbox, 'diode')
            diode.left += margin
            text = uiutil.GetChild(checkbox, 'text')
            text.left += margin

        uix.GetContainerHeader('Database Connection Details', connframe)
        textlist = [['Provider',
          'provider',
          None,
          self.db['Provider']],
         ['Data Source',
          'datasource',
          None,
          self.db['Data Source']],
         ['User ID',
          'userid',
          None,
          self.db['User ID']],
         ['DB Password',
          'dbpassword',
          '\x95',
          self.db['Password']],
         ['Initial Catalog',
          'initialcatalog',
          None,
          self.db['Initial Catalog']]]
        for line in textlist:
            (label, field, passwordchar, default,) = line
            obj = self.CustomEdit(configname=field, where=connframe, label=label, width=margin, left=margin, top=margin, height=20, align=uiconst.TOTOP, labelleft=True, passwordChar=passwordchar, setvalue=default)
            setattr(self, field, obj)

        uicls.Container(name='push', align=uiconst.TOTOP, height=margin, parent=connframe)
        uix.GetContainerHeader('Test Server Details', connframe)
        self.server = self.CustomEdit(configname='server', where=connframe, label='Server:', width=margin, left=margin, top=margin, height=20, align=uiconst.TOTOP, labelleft=True, setvalue=self.account['server'])
        uicls.Container(name='push', align=uiconst.TOTOP, height=margin, parent=connframe)
        uix.GetContainerHeader('Test Account Details', connframe)
        textlist = [['Username',
          'username',
          None,
          self.account['user']],
         ['Password',
          'password',
          '\x95',
          self.account['password']],
         ['Character',
          'character',
          None,
          self.account['character']]]
        for line in textlist:
            (label, field, passwordchar, default,) = line
            obj = self.CustomEdit(configname=field, where=connframe, label=label, width=margin, left=margin, top=margin, height=20, align=uiconst.TOTOP, labelleft=True, passwordChar=passwordchar, setvalue=default)
            setattr(self, field, obj)

        uicls.Container(name='push', align=uiconst.TOTOP, height=margin, parent=connframe)
        uix.GetContainerHeader('YAML Data File [for next benchmark]', connframe)
        yamlName = prefs.GetValue('bmyamlname', 'None')
        yamlKey = prefs.GetValue('bmyamlkey', 'None')
        yaml_cont = uicls.Container(name='yamlInfo', parent=connframe, align=uiconst.TOTOP, height=28)
        push = uicls.Container(name='push', align=uiconst.TOTOP, height=margin, parent=yaml_cont)
        textStr = ('\x95 File: %s<br>\x95 Key: %s' % (os.path.basename(yamlName), yamlKey))
        textHint = ('<b>File:</b>%s<br><b>Key:</b>%s' % (yamlName, yamlKey))
        self.yaml = uicls.Label(text=textStr, parent=yaml_cont, align=uiconst.TOLEFT, width=280, left=margin, fontsize=10, letterspace=1, linespace=9, uppercase=1, state=uiconst.UI_NORMAL)
        self.yaml.hint = textHint
        icon_cont = uicls.Container(name='refreshIcon', parent=yaml_cont, align=uiconst.TORIGHT, height=24, width=24, left=margin)
        uicls.Frame(parent=icon_cont, color=(1.0, 1.0, 1.0, 0.125))
        icon = uicls.Icon(icon='ui_44_32_05', parent=icon_cont, size=24, left=-1, top=-1)
        icon.hint = 'Refresh YAML Information'
        icon.OnClick = self.UpdateYamlString
        icon.OnMouseEnter = (self.ShowSelected, 1)
        icon.OnMouseExit = (self.ShowSelected, 0)
        icon.sr.hilite = uicls.Fill(parent=icon_cont, name='hilite', state=uiconst.UI_HIDDEN)
        btns = [['Delete All',
          self.Delete,
          None,
          81],
         ['Save',
          self.Save,
          None,
          81],
         ['Use current',
          self.UseCurrent,
          None,
          81]]
        buttons = uix.MakeBtnGroup(btns, where=connframe)
        buttons.height = 20
        delbtn = uiutil.GetChild(self, 'Delete All_Btn')
        delbtn.hint = ['<color=0xffff0000>WARNING!</color><br><br>This button will delete all the benchmark details from the prefs.ini!'][0]
        savebtn = uiutil.GetChild(self, 'Save_Btn')
        savebtn.hint = '</color>This button will save all the above details to prefs.ini.'
        self.LockHeight(self.height)
        self.settingup = False
        for checkbox in [self.nextcb,
         self.rescb,
         self.filecb,
         self.databasecb]:
            func = checkbox.OnChange
            func(checkbox)




    def ShowSelected(self, toggle, btn, *args):
        btn.sr.hilite.state = [uix.UI_HIDDEN, uix.UI_DISABLED][toggle]



    def UpdateYamlString(self, *args):
        yamlName = prefs.GetValue('bmyamlname', 'None')
        yamlKey = prefs.GetValue('bmyamlkey', 'None')
        textStr = ('\x95 File: %s<br>\x95 Key: %s' % (os.path.basename(yamlName), yamlKey))
        textHint = ('<b>File:</b>%s<br><b>Key:</b>%s' % (yamlName, yamlKey))
        self.yaml.text = textStr
        self.yaml.hint = textHint



    def GenerateTree(self, node, *args):
        keys = ['bmaccount',
         'bmdbconn',
         'bmnextrun',
         'bmoutput',
         'bmreslock',
         'bmyamlname',
         'bmyamlkey']
        public = ['public']
        generic = ['generic']
        bmfile = ['eveBenchmarkFileName']
        content = []
        level = 1
        if (node is None):
            rows = ['prefs', 'settings']
        else:
            level = (node.sublevel + 1)
            if (node.sublevel == 1):
                if (node.id == 'prefs'):
                    rows = keys
                else:
                    if (node.id == 'settings'):
                        rows = public
            elif (node.sublevel == 2):
                rows = generic
            else:
                rows = bmfile
        if (level == 1):
            for row in rows:
                entries = {'label': row,
                 'id': row,
                 'sublevel': level}
                self._BenchmarkDetails__InsertGroup(content, supplementalFields=entries)

        else:
            for row in rows:
                data = util.KeyVal()
                sublevel = (node.sublevel + 1)
                entries = {'label': row,
                 'id': row,
                 'sublevel': sublevel}
                if (node.sublevel == 1):
                    if (node.id == 'prefs'):
                        val = prefs.GetValue(row, '')
                        entries = [('sublevel', sublevel),
                         ('label', ('%s<t>%s' % (row, val))),
                         ('hint', ('%s<t>%s' % (row, val))),
                         ('GetMenu', self.GetTreeMenu),
                         ('OnDblClick', self.DoTreeNodeEdit),
                         ('_key', row),
                         ('_value', val),
                         ('_type', 'prefs')]
                        self._BenchmarkDetails__InsertGeneric(content, data, entries)
                    else:
                        if (node.id == 'settings'):
                            self._BenchmarkDetails__InsertGroup(content, supplementalFields=entries)
                elif (node.sublevel == 2):
                    self._BenchmarkDetails__InsertGroup(content, supplementalFields=entries)
                else:
                    if (node.sublevel == 3):
                        val = settings.public.generic.Get(row, '')
                        entries = [('sublevel', sublevel),
                         ('label', ('%s<t>%s' % (row, val))),
                         ('hint', ('%s : %s' % (row, val))),
                         ('GetMenu', self.GetTreeMenu),
                         ('OnDblClick', self.DoTreeNodeEdit),
                         ('_key', row),
                         ('_value', val),
                         ('_type', 'settings')]
                        self._BenchmarkDetails__InsertGeneric(content, data, entries)

        return content



    def __InsertGroup(self, listToAppendTo, data = None, supplementalFields = None):
        if (data is None):
            data = {'GetSubContent': self.GenerateTree,
             'groupItems': [],
             'showlen': False,
             'state': 'locked',
             'selected': 1,
             'hideExpander': True,
             'BlockOpenWindow': 1,
             'hideFill': True}
        if (supplementalFields is not None):
            data.update(supplementalFields)
        listToAppendTo.append(listentry.Get('Group', data))



    def __InsertGeneric(self, listToAppendTo, data, supplementalFields = None):
        if (supplementalFields is not None):
            for (k, v,) in supplementalFields:
                data.Set(k, v)

        listToAppendTo.append(listentry.Get('Generic', data=data))



    def GetTreeMenu(self, node, *args):
        m = []
        m.append(('Copy',
         self.DoTreeNodeCopy,
         (node)))
        m.append(None)
        m.append(('Edit Value',
         self.DoTreeNodeEdit,
         (node)))
        m.append(('Reset Value',
         self.DoTreeNodeReset,
         (node)))
        m.append(None)
        m.append(('Rename Key',
         self.DoTreeNodeRename,
         (node)))
        m.append(('Delete Key',
         self.DoTreeNodeDelete,
         (node)))
        return m



    def DoTreeNodeCopy(self, node, *args):
        n = node.sr.node
        copyStr = ('%s=%s' % (n._key, n._value))
        blue.pyos.SetClipboardData(copyStr)



    def DoTreeNodeEdit(self, node, *args):
        n = node.sr.node
        ret = uix.NamePopup(caption=('Edit %s' % n._key), label=("Specify a value for '%s'" % n._key), setvalue=('%s' % n._value))
        if (ret is not None):
            if (n._type == 'prefs'):
                prefs.SetValue(n._key, ret['name'])
            else:
                if (n._type == 'settings'):
                    settings.public.generic.Set(n._key, ret['name'])
        self.DoTreeRefresh()



    def DoTreeNodeReset(self, node, *args):
        n = node.sr.node
        header = 'Reset this entry?'
        question = ("Are you sure you want to reset the value for '%s'?" % n._key)
        if not (eve.Message('CustomQuestion', {'header': header,
         'question': question}, uix.YESNO) == uix.ID_YES):
            return 
        if (n._type == 'prefs'):
            prefs.SetValue(n._key, '')
        elif (n._type == 'settings'):
            settings.public.generic.Set(n._key, '')
        self.DoTreeRefresh()



    def DoTreeNodeRename(self, node, *args):
        n = node.sr.node
        header = 'Rename this key?'
        question = ("Are you sure you want to rename '%s'?<br>It will no longer be picked up by the benchmark and as such it is not advised." % n._key)
        if not (eve.Message('CustomQuestion', {'header': header,
         'question': question}, uix.YESNO) == uix.ID_YES):
            return 
        ret = uix.NamePopup(caption=('Rename %s' % n._key), label=("Specify a new name for '%s'" % n._key), setvalue=('%s' % n._key))
        if (ret is not None):
            if (ret['name'].lower() == n._key.lower()):
                eve.Message('CustomNotify', {'notify': 'Your chosen new name is the same as the old name. That was silly.'})
                return 
            if (n._type == 'prefs'):
                prefs.SetValue(ret['name'], n._value)
                prefs.DeleteValue(n._key)
            else:
                if (n._type == 'settings'):
                    settings.public.generic.Set(ret['name'], n._value)
                    settings.public.generic.Delete(n._key)
        self.DoTreeRefresh()



    def DoTreeNodeDelete(self, node, *args):
        n = node.sr.node
        header = 'Delete this key?'
        question = ("Are you sure you want to <b>permanently</b> delete the '%s' key?<br>You can not undo this!" % n._key)
        if not (eve.Message('CustomQuestion', {'header': header,
         'question': question}, uix.YESNO) == uix.ID_YES):
            return 
        if (n._type == 'prefs'):
            prefs.DeleteValue(n._key)
        elif (n._type == 'settings'):
            settings.public.generic.Delete(n._key)
        self.DoTreeRefresh()



    def DoTreeRefresh(self, *args):
        tree = self.GenerateTree(None, False)
        self.tree.Load(contentList=tree, headers=['Key', 'Value'])



    def DoAddBenchmark(self, id, defDict = None, *args):
        if (defDict is not None):
            idx = defDict['idx']
            id = defDict['id']
            name = self.order[id]
            duration = defDict['duration']
            scale = defDict['scale']
            type = defDict['type']
        else:
            idx = (len(self.scroll.sr.entries) + 1)
            name = self.order[id]
            duration = 1
            scale = 0
            type = 0
        units = ['minutes', 'iterations'][scale]
        infoStr = ('%s %s' % (duration, units))
        data = util.KeyVal()
        data.info = {'id': id,
         'idx': idx,
         'type': type,
         'duration': duration,
         'scale': scale}
        data.scale = scale
        data.infoStr = infoStr
        data.label = ('%s<t>%s<t>%s<t>%s' % (idx,
         name,
         self.types[type],
         infoStr))
        data.hint = ('%s: %s' % (type, name))
        data.GetMenu = self.GetBenchmarkMenu
        data.OnDblClick = self.SetBenchmarkDuration
        self.scroll.sr.entries.append(listentry.Get('Generic', data=data))
        self.DoScrollRefresh()



    def GetBenchmarkMenu(self, node, *args):
        m = []
        m.append(('Set duration',
         self.SetBenchmarkDuration,
         (node)))
        m.append(('Remove',
         self._DoScrollRemove,
         (node.sr.node,
          True,
          True)))
        return m



    def SetBenchmarkDuration(self, node, *args):
        node = node.sr.node
        bm = BenchmarkPopup()
        ret = bm.Wnd()
        if ret:
            duration = int(ret['_duration'])
            scale = ret['_scale']
            units = ['minutes', 'iterations'][scale]
            info = node.info
            info['duration'] = duration
            info['scale'] = scale
            node.infoStr = ('%s %s' % (duration, units))
            node.label = ('%s<t>%s<t>%s<t>%s' % (info['idx'],
             self.order[info['id']],
             self.types[info['type']],
             node.infoStr))
            self.DoScrollRefresh()



    def DoEffectToggle(self, configname, defDict = None, *args):
        if (defDict is not None):
            idx = defDict['idx']
            configname = defDict['id']
            name = self.toggle[configname]
            setting = defDict['setting']
            type = defDict['type']
        else:
            idx = (len(self.scroll.sr.entries) + 1)
            name = self.toggle[configname]
            type = 1
            setting = 1
        infoStr = ['Set to False', 'Set to True'][setting]
        data = util.KeyVal()
        data.info = {'id': configname,
         'idx': idx,
         'type': type,
         'setting': setting}
        data.infoStr = infoStr
        data.label = ('%s<t>%s<t>%s<t>%s' % (idx,
         name,
         self.types[type],
         infoStr))
        data.hint = ('%s: %s' % (type, name))
        data.GetMenu = self.GetEffectMenu
        data.OnDblClick = self.DoEffectState
        self.scroll.sr.entries.append(listentry.Get('Generic', data=data))
        self.DoScrollRefresh()



    def GetEffectMenu(self, node, *args):
        m = []
        m.append(('Define State',
         self.DoEffectState,
         (node)))
        m.append(('Remove',
         self._DoScrollRemove,
         (node.sr.node,
          True,
          True)))
        return m



    def DoEffectState(self, node, *args):
        node = node.sr.node
        info = node.info
        name = self.toggle[info['id']]
        cur = settings.user.ui.Get(info['id'], 1)
        eff = EffectPopup(current=cur)
        ret = eff.Wnd()
        if ret:
            node.info['setting'] = state = (not ret['_logic'])
            node.infoStr = ['Set to False', 'Set to True'][state]
            node.label = ('%s<t>%s<t>%s<t>%s' % (info['idx'],
             self.toggle[info['id']],
             self.types[info['type']],
             node.infoStr))
            self.DoScrollRefresh()



    def DoScrollRefresh(self, *args):
        self.scroll.Load(contentList=self.scroll.sr.entries, headers=['ID',
         'Event',
         'Type',
         'Info'], noContentHint=mls.UI_CORP_NOITEMSFOUND)



    def DoScrollAdd(self, *args):
        m = []
        n = []
        o = []
        ordered = self.order.keys()[:]
        ordered.sort()
        for id in ordered:
            n.append((self.order[id],
             self.DoAddBenchmark,
             (id)))

        effects = self.toggle.keys()[:]
        effects.sort()
        for setting in effects:
            name = self.toggle[setting]
            o.append((name,
             self.DoEffectToggle,
             (setting)))

        m.extend([('Benchmarks', n),
         None,
         ('Effects', o)])
        self.CreatePopup('Add Event', m)



    def DoScrollRemove(self, *args):
        nodes = self.scroll.GetSelected()
        if (len(nodes) == 0):
            eve.Message('CustomNotify', {'notify': 'You must select an entry to remove it. You cannot since there are no entries here.'})
            return 
        ret = self._DoScrollRemove(nodes[0], ask=True)
        self.DoScrollIdxRefresh()
        if ret:
            self.DoScrollRefresh()
        else:
            self.scroll.SelectNode(nodes[0])



    def _DoScrollRemove(self, node, refresh = False, ask = False, *args):
        if ask:
            header = 'Remove this entry?'
            question = 'Are you sure you want to remove the selected entry?'
            if not (eve.Message('CustomQuestion', {'header': header,
             'question': question}, uix.YESNO) == uix.ID_YES):
                return 0
            self.scroll.sr.entries.pop(node.idx)
            if refresh:
                self.DoScrollRefresh()
            return 1



    def DoScrollIdxRefresh(self, *args):
        nodes = self.scroll.sr.entries
        if (len(nodes) > 0):
            for entry in nodes:
                info = entry.info
                idx = (nodes.index(entry) + 1)
                this = ['order', 'toggle'][info['type']]
                dict = getattr(self, this)
                name = dict[info['id']]
                details = entry.infoStr
                entry.label = ('%s<t>%s<t>%s<t>%s' % (idx,
                 name,
                 self.types[info['type']],
                 details))
                entry.info['idx'] = idx

        self.DoScrollRefresh()



    def DoScrollClear(self, ask = True, *args):
        if ((len(self.scroll.sr.entries) == 0) and ask):
            eve.Message('CustomNotify', {'notify': 'The list is already empty.'})
            return 
        if ask:
            header = 'Clear all entries?'
            question = 'Are you sure you want to clear all the entries from the list?'
            if not (eve.Message('CustomQuestion', {'header': header,
             'question': question}, uix.YESNO) == uix.ID_YES):
                return 
        self.scroll.Load(contentList=[], headers=['ID',
         'Event',
         'Type',
         'Info'], noContentHint=mls.UI_CORP_NOITEMSFOUND)



    def DoNodeMoveUp(self, *args):
        if (len(self.scroll.sr.entries) in (0, 1)):
            eve.Message('CustomNotify', {'notify': 'There must be more than one entry in the list.'})
            return 
        nodes = self.scroll.GetSelected()
        if (len(nodes) == 0):
            eve.Message('CustomNotify', {'notify': 'Please select an entry before attempting to move it.'})
            return 
        node = nodes[0]
        if (node.info['idx'] <= 1):
            eve.Message('CustomNotify', {'notify': 'You cannot move this entry any higher, it is the first one.'})
            return 
        self.DoNodeMove(node, -1)
        self.DoScrollRefresh()
        self.scroll.SelectNode(node)



    def DoNodeMoveDown(self, *args):
        if (len(self.scroll.sr.entries) in (0, 1)):
            eve.Message('CustomNotify', {'notify': 'There must be more than one entry in the list.'})
            return 
        nodes = self.scroll.GetSelected()
        if (len(nodes) == 0):
            eve.Message('CustomNotify', {'notify': 'Please select an entry before attempting to move it.'})
            return 
        node = nodes[0]
        if (node.idx == (len(self.scroll.sr.entries) - 1)):
            eve.Message('CustomNotify', {'notify': 'You cannot move this entry any lower, it is the last one.'})
            return 
        self.DoNodeMove(node, 1)
        self.DoScrollRefresh()
        self.scroll.SelectNode(node)



    def DoNodeMove(self, srcNode, direction, *args):
        dIdx = srcNode.info['idx']
        aIdx = self.scroll.sr.entries.index(srcNode)
        sdIdx = (dIdx + direction)
        saIdx = (aIdx + direction)
        dstNode = self.scroll.GetNode(saIdx)
        e = self.scroll.sr.entries
        (e[saIdx], e[aIdx],) = (e[aIdx], e[saIdx])
        for n in [srcNode, dstNode]:
            self.UpdateNodeLabel(n)




    def DoDefaultSet(self, *args):
        if (len(self.store) == 0):
            eve.Message('CustomNotify', {'notify': 'There are no stored configurations.'})
            return 
        m = []
        keys = self.store.keys()[:]
        keys.sort()
        for key in keys:
            m.append((key,
             self._DoDefaultSet,
             (key)))

        self.CreatePopup('Set As Default Key', m)



    def _DoDefaultSet(self, key, *args):
        if (self.file is None):
            eve.Message('CustomNotify', {'notify': 'Please export to YAML first, then set the default.'})
            return 
        header = 'Set as default'
        question = ('Do you want to set thie configuration [%s] as the default?<br><br>It will also set [%s] as the default YAML file.' % (key, self.file))
        if not (eve.Message('CustomQuestion', {'header': header,
         'question': question}, uix.YESNO) == uix.ID_YES):
            return 
        prefs.SetValue('bmyamlkey', key)
        prefs.SetValue('bmyamlname', self.file)
        self.DoTreeRefresh()



    def DoDeleteFromStore(self, *args):
        m = []
        keys = self.store.keys()[:]
        keys.sort()
        for key in keys:
            m.append((key,
             self._DoDeleteFromStore,
             (key)))

        if (len(m) == 0):
            eve.Message('CustomNotify', {'notify': 'There are no configurations to delete.'})
        else:
            self.CreatePopup('Delete Key', m)



    def _DoDeleteFromStore(self, key, ask = True, *args):
        if ask:
            header = 'Delete this configuration?'
            question = 'Are you sure you want to <b>permanently</b delete the selected configuration?'
            if not (eve.Message('CustomQuestion', {'header': header,
             'question': question}, uix.YESNO) == uix.ID_YES):
                return 
        del self.store[key]



    def DoLoadFromStore(self, *args):
        m = []
        keys = self.store.keys()[:]
        keys.sort()
        for key in keys:
            m.append((key,
             self._DoLoadFromStore,
             (key)))

        if (len(m) == 0):
            eve.Message('CustomNotify', {'notify': 'There are no configurations to load. Try importing a YAML data file.'})
        else:
            self.CreatePopup('Load Key', m)



    def _DoLoadFromStore(self, key, *args):
        self.DoScrollClear(ask=False)
        keys = self.store[key].keys()
        keys.sort()
        for k in keys:
            type = self.store[key][k]['type']
            if (type == 0):
                self.DoAddBenchmark(0, defDict=self.store[key][k])
            else:
                if (type == 1):
                    self.DoEffectToggle(0, defDict=self.store[key][k])




    def DoSaveToStore(self, *args):
        if (len(self.scroll.sr.entries) == 0):
            eve.Message('CustomNotify', {'notify': 'The list is empty, nubbins.'})
            return 
        ret = uix.NamePopup('Save as...', 'Specify a name for this configuration')
        if (ret is None):
            return 
        name = str(ret['name'])
        if (name in self.store):
            header = 'Duplicate entry'
            question = ("There is already a configuration called '%s'. Do you want to overwrite it?" % name)
            if not (eve.Message('CustomQuestion', {'header': header,
             'question': question}, uix.YESNO) == uix.ID_YES):
                return 
        setup = {}
        for node in self.scroll.sr.entries:
            setup[node.info['idx']] = node.info

        self.store[name] = setup.copy()



    def DoYamlImport(self, *args):
        DIR = sm.StartService('insider').GetInsiderDir()
        _NAME = os.path.join(DIR, OUTPUT_FILE)
        NAME = prefs.GetValue('bmyamlname', _NAME)
        TARGET = os.path.join(DIR, NAME)
        ret = uix.NamePopup('Open file...', 'Specify the name of the YAML data file', TARGET)
        if (ret is None):
            return 
        if not os.path.exists(ret['name']):
            eve.Message('CustomNotify', {'notify': 'The specified file does not exist.'})
            return 
        inputfile = file(ret['name'], 'r')
        self.store = yaml.load(inputfile)
        inputfile.close()
        if (len(self.store.keys()) == 1):
            key = self.store.keys()[0]
            self._DoLoadFromStore(key)
        self.file = ret['name']



    def DoYamlExport(self, *args):
        DIR = sm.StartService('insider').GetInsiderDir()
        _NAME = os.path.join(DIR, OUTPUT_FILE)
        NAME = prefs.GetValue('bmyamlname', _NAME)
        TARGET = os.path.join(DIR, NAME)
        ret = uix.NamePopup('Save to...', 'Specify the name of the YAML data file', TARGET)
        if (ret is None):
            return 
        o = file(ret['name'], 'w')
        yaml.dump(self.store, o, default_flow_style=False)
        o.close()
        header = 'Set as default'
        question = ('Do you want to set this file as the default file? (%s)<br><br>This file is used to determine the benchmark executed at the next benchmarking attempt.' % ret['name'])
        if (eve.Message('CustomQuestion', {'header': header,
         'question': question}, uix.YESNO) == uix.ID_YES):
            prefs.SetValue('bmyamlname', ret['name'])
            self.UpdateYamlString()
            self.DoTreeRefresh()
            self.file = ret['name']



    def UpdateNodeLabel(self, node, *args):
        idx = (self.scroll.sr.entries.index(node) + 1)
        info = node.info
        dictToUse = ['order', 'toggle'][info['type']]
        dictInUse = getattr(self, dictToUse)
        node.label = ('%s<t>%s<t>%s<t>%s' % (idx,
         dictInUse[info['id']],
         self.types[info['type']],
         node.infoStr))
        node.info['idx'] = idx



    def CreatePopup(self, anchor, lst, *args):
        if (len(lst) == 0):
            return 
        mv = menu.CreateMenuView(menu.CreateMenuFromList(lst), None, None)
        anchoritem = uiutil.GetChild(self, anchor)
        (x, y, w, h,) = anchoritem.GetAbsolute()
        x = max(x, 0)
        y = (y + h)
        if ((y + mv.height) > eve.triapp.uilib.desktop.height):
            mv.top = (anchoritem.GetAbsolute()[1] - mv.height)
        else:
            mv.top = y
        mv.left = min((eve.triapp.uilib.desktop.width - mv.width), x)
        uicls.Frame(parent=mv, color=(1.0, 1.0, 1.0, 0.2))
        uicore.layer.menu.children.insert(0, mv)



    def CustomEdit(self, configname, where, setvalue = None, left = 0, width = 80, top = 2, height = 18, ints = None, floats = None, callback = None, label = None, maxLength = None, passwordChar = None, align = 0, readonly = 0, adjustWidth = False, labelleft = None, labeloffset = 90):
        name = ('%sParent' % configname)
        container = uicls.Container(name=name, parent=where, align=align, height=height)
        parent = uicls.SinglelineEdit(name=configname, parent=container, setvalue=setvalue, left=left, width=width, ints=ints, top=top, height=height, floats=floats, OnChange=callback, label=label, maxLength=maxLength, passwordCharacter=passwordChar, align=uiconst.TOALL, readonly=readonly, adjustWidth=adjustWidth)
        if (labelleft is not None):
            label = parent.sr.label
            label.left = -((labeloffset - const.defaultPadding) - left)
            label.top = 1
            label.width = labeloffset
            parent.left = labeloffset
        return parent



    def Modes(self, *args):
        modes = prefs.GetValue('bmoutput', None)
        if (modes is None):
            return (0, 0)
        else:
            try:
                (database, file,) = modes.split(':')
            except (ValueError), e:
                sys.exc_clear()
                database = 0
                file = 0
            return [int(database), int(file)]



    def UseCurrent(self, *args):
        server = util.GetServerName()
        user = sm.RemoteSvc('userSvc').GetUserName(eve.session.userid)
        character = cfg.eveowners.Get(eve.session.charid).name
        fields = [('server', server),
         ('username', user),
         ('password', ''),
         ('character', character)]
        for (entry, value,) in fields:
            a = getattr(self, entry)
            a.SetValue(value)




    def Validate(self, fields, *args):
        errorCount = 0
        for input in fields:
            self.data[input] = ''
            field = getattr(self, input, None)
            if (field is None):
                return 
            value = field.GetValue()
            if ((value in ('', ' ', None)) and (len(value) == 0)):
                errorCount += 1
            self.data[input] = value

        if (errorCount != 0):
            return True
        else:
            return False



    def Save(self, *args):
        info = []
        database = ['provider',
         'datasource',
         'userid',
         'dbpassword',
         'initialcatalog']
        dbFieldError = self.Validate(database)
        server = ['server',
         'username',
         'password',
         'character']
        serverFieldError = self.Validate(server)
        checked = self.databasecb.GetValue()
        if (checked and dbFieldError):
            info += ['All database fields must be filled in.']
        elif (checked and (not dbFieldError)):
            dbconn = ('Provider=%s;Data Source=%s;User ID=%s;Password=%s;Initial Catalog=%s' % (self.data['provider'],
             self.data['datasource'],
             self.data['userid'],
             self.data['dbpassword'],
             self.data['initialcatalog']))
            prefs.SetValue('bmdbconn', dbconn)
        if serverFieldError:
            info += ['All account and server details must be filled in.']
        else:
            output = ('%s:%s:%s:%s' % (self.data['server'],
             self.data['username'],
             self.data['password'],
             self.data['character']))
            prefs.SetValue('bmaccount', output)
        if ((checked and dbFieldError) or serverFieldError):
            text = '<br>'.join(info)
            eve.Message('CustomInfo', {'info': text})
        self.DoTreeRefresh()



    def Delete(self, *args):
        header = 'Delete all settings?'
        warning = 'Are you sure you want to <b>permanently</b> delete all details? They can not be recovered!'
        if not (eve.Message('CustomWarning', {'header': header,
         'warning': warning}, uix.YESNO) == uix.ID_YES):
            return 
        for key in ['provider',
         'datasource',
         'userid',
         'password',
         'dbpassword',
         'initialcatalog']:
            obj = getattr(self, key)
            obj.SetValue('')

        for key in ['server',
         'username',
         'password',
         'character']:
            obj = getattr(self, key)
            obj.SetValue('')

        for checkbox in [self.nextcb,
         self.rescb,
         self.filecb,
         self.databasecb]:
            checkbox.SetValue(0)

        for key in ['bmaccount',
         'bmdbconn',
         'bmnextrun',
         'bmoutput',
         'bmreslock',
         'bmyamlname',
         'bmyamlkey']:
            prefs.DeleteValue(key)

        settings.public.generic.Delete('eveBenchmarkFileName')
        self.UpdateYamlString()
        self.DoTreeRefresh()



    def DoNextLogonChange(self, cb):
        if self.settingup:
            return 
        checked = cb.GetValue()
        prefs.SetValue('bmnextrun', checked)
        if checked:
            cb.hint = ['Benchmark at next logon: <color=0xff00ff00>ENABLED</color><br><br>With this enabled the benchmark<br>suite will automatically startat the next client logon.'][0]
        else:
            cb.hint = ['Benchmark at next logon: <color=0xffff0000>DISABLED</color><br><br>With this disabled the benchmark<br>suite will not run automatically at the next client logon.'][0]
        cb.state = uix.UI_HIDDEN
        cb.state = uix.UI_NORMAL
        self.DoTreeRefresh()



    def DoResolutionChange(self, cb):
        if self.settingup:
            return 
        checked = cb.GetValue()
        prefs.SetValue('bmreslock', checked)
        if checked:
            cb.hint = ['Resolutions Unlocked: <color=0xff00ff00>YES</color><br><br>With this enabled the benchmark suite<br>will run through a series of tests at<br>varying resolutions.'][0]
        else:
            cb.hint = [('Resolutions Unlocked: <color=0xffff0000>NO</color><br><br>With this disabled the benchmark<br>suite will only run at the current<br>resolution. (%s x %s)' % (eve.triapp.width, eve.triapp.height))][0]
        cb.state = uix.UI_HIDDEN
        cb.state = uix.UI_NORMAL
        self.DoTreeRefresh()



    def DoFileSaveChange(self, cb):
        if self.settingup:
            return 
        checked = cb.GetValue()
        (dbop, fiop,) = self.Modes()
        if checked:
            cb.hint = ['Save to file: <color=0xff00ff00>ENABLED</color><br><br>With this enabled the benchmark suite<br>will save results to a file.'][0]
            fiop = 1
            prefs.SetValue('bmoutput', ('%s:%s' % (dbop, fiop)))
        else:
            cb.hint = ['Save to file: <color=0xffff0000>DISABLED</color><br><br>With this disabled the benchmark suite<br>will not save results to a file.'][0]
            fiop = 0
            prefs.SetValue('bmoutput', ('%s:%s' % (dbop, fiop)))
        cb.state = uix.UI_HIDDEN
        cb.state = uix.UI_NORMAL
        self.DoTreeRefresh()



    def DoDatabaseSaveChange(self, cb):
        if self.settingup:
            return 
        checked = cb.GetValue()
        (dbop, fiop,) = self.Modes()
        prefs.SetValue('bmoutput', ('%s:%s' % (checked, fiop)))
        if checked:
            database = ['provider',
             'datasource',
             'userid',
             'dbpassword',
             'initialcatalog']
            error = self.Validate(database)
            if not error:
                cb.hint = ['Save to database: <color=0xff00ff00>ENABLED</color><br><br>With this enabled the benchmark suite<br>will save results to the database.'][0]
            else:
                cb.SetValue(0)
        else:
            cb.hint = ['Save to database: <color=0xffff0000>DISABLED</color><br><br>With this disabled the benchmark suite<br>will not save results to the database.<br><br>This can not be enabled until all the fields below have data.'][0]
        cb.state = uix.UI_HIDDEN
        cb.state = uix.UI_NORMAL
        self.DoTreeRefresh()



    def GetDetails(self, *args):
        self.GetAccount()
        self.GetDatabase()



    def GetAccount(self, *args):
        keys = ['server',
         'user',
         'password',
         'character']
        account = prefs.GetValue('bmaccount', None)
        if (account is None):
            for key in keys:
                self.account[key] = ''

            return 
        try:
            (server, user, password, character,) = account.split(':')
            self.account['server'] = server
            self.account['user'] = user
            self.account['password'] = password
            self.account['character'] = character
        except (ValueError), e:
            sys.exc_clear()



    def GetDatabase(self, *args):
        keys = ['User ID',
         'Data Source',
         'Password',
         'Initial Catalog',
         'Provider']
        for key in keys:
            self.db[key] = ''

        dbconn = prefs.GetValue('bmdbconn', None)
        if (dbconn is None):
            return 
        try:
            for kv in dbconn.split(';'):
                k = kv.split('=')[0]
                v = kv.split('=')[1]
                if (k in self.db):
                    self.db[k] = v
                else:
                    logStr = ('Unexpected key detected whilst parsing DB string: %s' % k)
                    logChannel.Log(logStr, log.LGWARN)

        except (StandardError), e:
            logStr = ('DB connection string is badly formatted: %s' % dbconn)
            logChannel.Log(logStr, log.LGERR)
            sys.exc_clear()
            for key in keys:
                self.db[key] = ''





class BenchmarkPopup:

    def __init__(self, caption = None):
        if (caption is None):
            caption = 'Benchmark Duration'
        format = [{'type': 'header',
          'text': 'Select how long you want the benchmark to run for',
          'frame': 1},
         {'type': 'checkbox',
          'required': 1,
          'key': 0,
          'text': 'Time (minutes)',
          'group': '_scale',
          'frame': 1,
          'setvalue': 1},
         {'type': 'checkbox',
          'required': 1,
          'key': 1,
          'text': 'Iterations (loops)',
          'group': '_scale',
          'frame': 1,
          'setvalue': 0},
         {'type': 'edit',
          'intonly': [1, 1000],
          'key': '_duration',
          'setvalue': '1',
          'label': 'Amount',
          'maxLength': 10,
          'frame': 1},
         {'type': 'push',
          'frame': 1},
         {'type': 'bbline'}]
        OKCANCEL = 1
        self.ret = uix.HybridWnd(format, caption, 1, None, OKCANCEL, None, minW=240, minH=80)



    def __getitem__(self, *args):
        return args



    def Wnd(self, *args):
        return self.ret




class EffectPopup:

    def __init__(self, caption = None, current = None):
        if (caption is None):
            caption = 'Effect State'
        if (current is None):
            default = 0
        else:
            default = current
        format = [{'type': 'header',
          'text': 'Specify the state you want the effect to be set to',
          'frame': 1},
         {'type': 'checkbox',
          'required': 1,
          'key': 0,
          'text': 'True',
          'group': '_logic',
          'frame': 1,
          'setvalue': default},
         {'type': 'checkbox',
          'required': 1,
          'key': 1,
          'text': 'False',
          'group': '_logic',
          'frame': 1,
          'setvalue': (not default)},
         {'type': 'push',
          'frame': 1},
         {'type': 'bbline'}]
        OKCANCEL = 1
        self.ret = uix.HybridWnd(format, caption, 1, None, OKCANCEL, None, minW=240, minH=80)



    def __getitem__(self, *args):
        return args



    def Wnd(self, *args):
        return self.ret




